<!--
 * @Author: Betty
 * @Date: 2020-11-13 23:15:42
 * @LastEditors: Betty
 * @LastEditTime: 2021-01-24 22:19:11
 * @Description: 带验证功能的表单组件
-->
<template>
  <form class="validate-form-container" autoComplete="off">
    <!-- 需要使用两个插槽，一个是插入input，一个插入提交按钮，所以要用名字区分它们 -->
    <!-- 因为默认有提交按钮，所以默认都插入input插槽，所以插入input的插槽是默认插槽 -->
    <slot name="default"></slot>
    <div class="submit-area" @click.prevent="submitForm">
      <!-- 插入提交按钮的插槽，后备内容是默认的提交按钮 -->
      <slot name="submit">
        <button type="submit" class="btn btn-primary">提交</button>
      </slot>
    </div>
  </form>
</template>

<script lang='ts'>
import mitt from 'mitt'
import { defineComponent, onMounted, onUnmounted, provide } from 'vue'
// 定义验证函数类型（显然是没有参数，返回值为布尔类型的函数）
type ValidateFunc = () => boolean
// 定义一个回调函数的参数的类型，里面不仅有验证函数，还有表单名字
interface CallbackProps {
  validator: ValidateFunc;
  formName: string;
}
// 创建一个emitter对象，来使用mitt的API
export const emitter = mitt()
export default defineComponent({
  name: '',
  emits: ['form-submit'],
  // 添加一个props叫name,也就是表单名字，用来作为表单标识,多表单的时候需要传入（与插槽类似）
  props: {
    name: {
      type: String,
      default: 'default'
    }
  },
  setup(props, context) {
    // 提供一个键值对，给子孙组件使用
    // 键名叫‘formname’，值为自己的name属性值，也就是自己这个表单的标识
    provide('formName', props.name)
    // 新建一个数组来存放input子组件的验证函数，类型为验证函数类型，默认为空数组
    let funcArr: ValidateFunc[] = []
    // 这个函数触发表单提交的自定义事件，事件参数是验证结果，是一个布尔值
    const submitForm = () => {
      // 触发自定义事件之前，我们先来循环调用验证函数数组，然后才得到结果
      // 应该用map函数，让它不忽略后面的函数，map方法得到的结果是验证结果数组，也就是布尔数组
      // 然后我们对这个布尔数组使用every判断是否每个值都是true，并把最后的结果传给父组件
      const result = funcArr.map((func) => func()).every((item) => item)
      console.log('form组件的验证结果是：', result) // 这里的验证无论如何都是true，没有验证到
      console.log('验证函数数组的长度是：',funcArr.length) // 问题是，这里的函数数组程度为0
      // 触发提交事件
      context.emit('form-submit', result)
    }
    // 定义监听"子组件初始化完成"的自定义事件的回调函数
    // 因为我们不一定会向回调函数里传入东西，所以可能是undefined，所以要写成可选参数或者写成与undefined的联合类型
    const callback = (obj: CallbackProps | undefined) => {
      // 判断是否传入了参数，并且参数的fromName属性是否是当前form的标识
      if (obj && obj.formName == props.name) {
        funcArr.push(obj.validator)
        console.log('收集了验证函数')// 如果有接收到验证函数，那么会有输出
      }
    }
    // 让input组件清空
    // const toClearInput = () => {
    //   emitter.emit('clear-input')
    // }
    // 让里面的input清空
    const resetForm = () => {
      emitter.emit('clear-input')
    }
    // 并不需要监听清空的事件，而是调用一个方法来让input清空
    // 监听清空的事件
    // emitter.on('ready-clear-input', toClearInput)
    // 使用mitt的API来创建事件监听
    emitter.on('form-item-created', callback)
    // 父组件的onMounted在子组件的onMounted之后触发
    onMounted(() => {
      console.log("输出emitter看看是否存在：");
      console.log(emitter)
    })
    onUnmounted(() => {
      // 在组件卸载的时候解除事件绑定
      emitter.off('form-item-created', callback)
      // 组件卸载后，让这个数组清空
      funcArr = []
    })
    return {
      submitForm,
      resetForm
    }
  }
})
</script>

<style>
</style>
